home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 9 / Example 9.2 / app.cpp next >
Encoding:
C/C++ Source or Header  |  2006-08-01  |  11.1 KB  |  433 lines

  1. //////////////////////////////////////////////////////////////
  2. // Example 9.2: Building Example                            //
  3. // Written by: C. Granberg, 2006                            //
  4. //////////////////////////////////////////////////////////////
  5.  
  6. #include <windows.h>
  7. #include <d3dx9.h>
  8. #include "debug.h"
  9. #include "shader.h"
  10. #include "terrain.h"
  11. #include "camera.h"
  12. #include "mouse.h"
  13. #include "building.h"
  14.  
  15. class APPLICATION
  16. {
  17.     public:
  18.         
  19.         APPLICATION();
  20.         HRESULT Init(HINSTANCE hInstance, int width, int height, bool windowed);
  21.         HRESULT Update(float deltaTime);
  22.         HRESULT Render();
  23.         HRESULT Cleanup();
  24.         HRESULT Quit();
  25.         DWORD FtoDword(float f){return *((DWORD*)&f);}
  26.  
  27.         void Select();
  28.         int GetBuilding();
  29.         void AddBuildings();
  30.  
  31.     private:
  32.         IDirect3DDevice9* m_pDevice; 
  33.         TERRAIN m_terrain;
  34.         CAMERA m_camera;
  35.         MOUSE m_mouse;
  36.         std::vector<BUILDING*> m_buildings;
  37.         BUILDING *m_pBuildToPlace;
  38.  
  39.         bool m_wireframe, m_placeBuilding;
  40.         DWORD m_time;
  41.         int m_fps, m_lastFps, m_placeType;
  42.         HWND m_mainWindow;
  43.         ID3DXFont *m_pFont;
  44.  
  45.         //Shaders
  46.         SHADER m_unitVS, m_unitPS;
  47.         D3DXHANDLE worldHandle, viewProjHandle, sunHandle, teamColHandle, vertexCol;
  48.  
  49. };
  50.  
  51. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd)
  52. {
  53.     APPLICATION app;
  54.  
  55.     if(FAILED(app.Init(hInstance, 800, 600, true)))
  56.         return 0;
  57.  
  58.     MSG msg;
  59.     memset(&msg, 0, sizeof(MSG));
  60.     int startTime = timeGetTime(); 
  61.  
  62.     while(msg.message != WM_QUIT)
  63.     {
  64.         if(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  65.         {
  66.             ::TranslateMessage(&msg);
  67.             ::DispatchMessage(&msg);
  68.         }
  69.         else
  70.         {    
  71.             int t = timeGetTime();
  72.             float deltaTime = (t - startTime)*0.001f;
  73.  
  74.             app.Update(deltaTime);
  75.             app.Render();
  76.  
  77.             startTime = t;
  78.         }
  79.     }
  80.  
  81.     app.Cleanup();
  82.  
  83.     return msg.wParam;
  84. }
  85.  
  86. APPLICATION::APPLICATION()
  87. {
  88.     m_pDevice = NULL; 
  89.     m_mainWindow = 0;
  90.     m_wireframe = m_placeBuilding = false;
  91.     srand(GetTickCount());
  92.     m_fps = m_lastFps = 0;
  93.     m_time = GetTickCount();
  94.     m_pBuildToPlace = NULL;
  95.     m_placeType = 0;
  96. }
  97.  
  98. HRESULT APPLICATION::Init(HINSTANCE hInstance, int width, int height, bool windowed)
  99. {
  100.     debug.Print("Application initiated");
  101.  
  102.     //Create Window Class
  103.     WNDCLASS wc;
  104.     memset(&wc, 0, sizeof(WNDCLASS));
  105.     wc.style         = CS_HREDRAW | CS_VREDRAW;
  106.     wc.lpfnWndProc   = (WNDPROC)::DefWindowProc; 
  107.     wc.hInstance     = hInstance;
  108.     wc.lpszClassName = "D3DWND";
  109.  
  110.     //Register Class and Create new Window
  111.     RegisterClass(&wc);
  112.     m_mainWindow = CreateWindow("D3DWND", "Example 9.2: Building Example", WS_EX_TOPMOST, 0, 0, width, height, 0, 0, hInstance, 0); 
  113.     SetCursor(NULL);
  114.     ShowWindow(m_mainWindow, SW_SHOW);
  115.     UpdateWindow(m_mainWindow);
  116.  
  117.     //Create IDirect3D9 Interface
  118.     IDirect3D9* d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
  119.  
  120.     if(d3d9 == NULL)
  121.     {
  122.         debug.Print("Direct3DCreate9() - FAILED");
  123.         return E_FAIL;
  124.     }
  125.  
  126.     //Check that the Device supports what we need from it
  127.     D3DCAPS9 caps;
  128.     d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
  129.  
  130.     //Hardware Vertex Processing or not?
  131.     int vp = 0;
  132.     if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
  133.         vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  134.     else vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  135.  
  136.     //Check vertex & pixelshader versions
  137.     if(caps.VertexShaderVersion < D3DVS_VERSION(2, 0) || caps.PixelShaderVersion < D3DPS_VERSION(2, 0))
  138.     {
  139.         debug.Print("Warning - Your graphic card does not support vertex and pixelshaders version 2.0");
  140.     }
  141.  
  142.     //Set D3DPRESENT_PARAMETERS
  143.     D3DPRESENT_PARAMETERS d3dpp;
  144.     d3dpp.BackBufferWidth            = width;
  145.     d3dpp.BackBufferHeight           = height;
  146.     d3dpp.BackBufferFormat           = D3DFMT_A8R8G8B8;
  147.     d3dpp.BackBufferCount            = 1;
  148.     d3dpp.MultiSampleType            = D3DMULTISAMPLE_NONE;
  149.     d3dpp.MultiSampleQuality         = 0;
  150.     d3dpp.SwapEffect                 = D3DSWAPEFFECT_DISCARD; 
  151.     d3dpp.hDeviceWindow              = m_mainWindow;
  152.     d3dpp.Windowed                   = windowed;
  153.     d3dpp.EnableAutoDepthStencil     = true; 
  154.     d3dpp.AutoDepthStencilFormat     = D3DFMT_D24S8;
  155.     d3dpp.Flags                      = 0;
  156.     d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
  157.     d3dpp.PresentationInterval       = D3DPRESENT_INTERVAL_IMMEDIATE;
  158.  
  159.     //Create the IDirect3DDevice9
  160.     if(FAILED(d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_mainWindow,
  161.                                  vp, &d3dpp, &m_pDevice)))
  162.     {
  163.         debug.Print("Failed to create IDirect3DDevice9");
  164.         return E_FAIL;
  165.     }
  166.  
  167.     //Release IDirect3D9 interface
  168.     d3d9->Release();
  169.  
  170.     D3DXCreateFont(m_pDevice, 18, 0, 0, 1, false,  
  171.                    DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
  172.                    DEFAULT_PITCH | FF_DONTCARE, "Arial", &m_pFont);
  173.  
  174.     LoadObjectResources(m_pDevice);
  175.     LoadMapObjectResources(m_pDevice);
  176.     LoadBuildingResources(m_pDevice);
  177.  
  178.     m_terrain.Init(m_pDevice, INTPOINT(100,100));
  179.  
  180.     m_mouse.InitMouse(m_pDevice, m_mainWindow);
  181.  
  182.     m_camera.Init(m_pDevice);
  183.     m_camera.m_focus = D3DXVECTOR3(50, 10, -50);
  184.     m_camera.m_fov = 0.6f;
  185.     m_camera.m_radius = 50.0f;
  186.  
  187.     //Set sampler state
  188.     for(int i=0;i<8;i++)
  189.     {
  190.         m_pDevice->SetSamplerState(i, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
  191.         m_pDevice->SetSamplerState(i, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
  192.         m_pDevice->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
  193.     }
  194.  
  195.     //Setup shaders
  196.     m_unitVS.Init(m_pDevice, "shaders/lighting.vs", VERTEX_SHADER);
  197.     worldHandle = m_unitVS.GetConstant("matW");
  198.     viewProjHandle = m_unitVS.GetConstant("matVP");
  199.     sunHandle = m_unitVS.GetConstant("DirToSun");
  200.     vertexCol = m_unitVS.GetConstant("vertexCol");
  201.  
  202.     m_unitPS.Init(m_pDevice, "shaders/teamCol.ps", PIXEL_SHADER);
  203.     teamColHandle = m_unitPS.GetConstant("tmCol");
  204.  
  205.     return S_OK;
  206. }
  207.  
  208. HRESULT APPLICATION::Update(float deltaTime)
  209. {        
  210.     //Control camera
  211.     m_camera.Update(m_mouse, m_terrain, deltaTime);
  212.     m_mouse.Update(m_terrain);
  213.  
  214.     if(KEYDOWN('W'))
  215.     {
  216.         m_wireframe = !m_wireframe;
  217.         Sleep(300);
  218.     }
  219.     if(KEYDOWN('1'))
  220.     {
  221.         m_placeType = 0;
  222.         m_placeBuilding = true;
  223.     }
  224.     if(KEYDOWN('2'))
  225.     {
  226.         m_placeType = 1;
  227.         m_placeBuilding = true;
  228.     }
  229.     if(KEYDOWN('3'))
  230.     {
  231.         m_placeType = 2;
  232.         m_placeBuilding = true;
  233.     }
  234.     else if(KEYDOWN(VK_SPACE))
  235.     {
  236.         m_terrain.GenerateRandomTerrain(9);
  237.  
  238.         for(int i=0;i<m_buildings.size();i++)
  239.             if(m_buildings[i] != NULL)
  240.                 delete m_buildings[i];
  241.         m_buildings.clear();
  242.     }
  243.     else if(KEYDOWN(VK_ESCAPE))
  244.     {
  245.         Quit();
  246.     }
  247.  
  248.     //Create building to place...
  249.     if(m_pBuildToPlace != NULL)delete m_pBuildToPlace;
  250.     m_pBuildToPlace = NULL;
  251.  
  252.     if(m_placeBuilding)
  253.         m_pBuildToPlace = new BUILDING(m_placeType, m_mouse.m_mappos, &m_terrain, false, m_pDevice);
  254.  
  255.     //Mouse input
  256.     if(m_mouse.ClickLeft() && m_placeBuilding)
  257.     {
  258.         m_mouse.DisableInput(300);
  259.  
  260.         if(PlaceOk(m_placeType, m_mouse.m_mappos, &m_terrain))
  261.         {
  262.             m_buildings.push_back(new BUILDING(m_placeType, m_mouse.m_mappos, &m_terrain, true, m_pDevice));
  263.             m_placeBuilding = false;
  264.         }
  265.     }
  266.     else if(m_mouse.ClickRight() && m_placeBuilding)
  267.         m_placeBuilding = false;
  268.  
  269.     return S_OK;
  270. }    
  271.  
  272. HRESULT APPLICATION::Render()
  273. {
  274.     // Clear the viewport
  275.     m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
  276.  
  277.     //FPS Calculation
  278.     m_fps++;
  279.     if(GetTickCount() - m_time > 1000)
  280.     {
  281.         m_lastFps = m_fps;
  282.         m_fps = 0;
  283.         m_time = GetTickCount();
  284.     }
  285.  
  286.     // Begin the scene 
  287.     if(SUCCEEDED(m_pDevice->BeginScene()))
  288.     {
  289.         if(m_wireframe)m_pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);    
  290.         else m_pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
  291.  
  292.         m_terrain.Render(m_camera);
  293.  
  294.         D3DXMATRIX world;
  295.         D3DXMatrixIdentity(&world);
  296.  
  297.         m_unitVS.SetMatrix(worldHandle, world);
  298.         m_unitVS.SetMatrix(viewProjHandle, m_camera.GetViewMatrix() * m_camera.GetProjectionMatrix());
  299.  
  300.         D3DXVECTOR3 sun;
  301.         D3DXVec3Normalize(&sun, &D3DXVECTOR3(0.5f, 1.0f, -0.5));
  302.         m_unitVS.SetVector3(sunHandle, sun);
  303.         m_unitPS.SetVector4(teamColHandle, D3DXVECTOR4(1.0f, 0.0f, 0.0f, 1.0f));
  304.         m_unitVS.SetVector4(vertexCol, D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f));
  305.  
  306.         m_unitVS.Begin();
  307.         m_unitPS.Begin();
  308.  
  309.         for(int i=0;i<m_buildings.size();i++)
  310.             if(m_buildings[i] != NULL && !m_camera.Cull(m_buildings[i]->GetBoundingBox()))
  311.             {
  312.                 m_unitVS.SetMatrix(worldHandle, m_buildings[i]->GetWorldMatrix());
  313.                 m_buildings[i]->Render();
  314.             }
  315.  
  316.         //Render building to place...
  317.         if(m_placeBuilding)
  318.         {
  319.             if(PlaceOk(m_placeType, m_mouse.m_mappos, &m_terrain))
  320.                 m_unitVS.SetVector4(vertexCol, D3DXVECTOR4(0.0f, 1.0f, 0.0f, 1.0f));
  321.             else m_unitVS.SetVector4(vertexCol, D3DXVECTOR4(1.0f, 0.0f, 0.0f, 1.0f));
  322.             m_unitVS.SetMatrix(worldHandle, m_pBuildToPlace->GetWorldMatrix());
  323.             m_pBuildToPlace->Render();
  324.         }        
  325.  
  326.         m_unitPS.End();
  327.         m_unitVS.End();
  328.  
  329.         //Draw selections
  330.         for(int i=0;i<m_buildings.size();i++)
  331.             if(m_buildings[i] != NULL && !m_camera.Cull(m_buildings[i]->GetBoundingBox()))
  332.                 m_buildings[i]->PaintSelected();
  333.  
  334.         Select();
  335.         m_mouse.Paint();
  336.  
  337.         RECT r[] = {{10, 10, 0, 0}, {10, 50, 0, 0}, {10, 70, 0, 0}, {10, 90, 0, 0}, {10, 110, 0, 0}, {720, 10, 0, 0}};
  338.         m_pFont->DrawText(NULL, "Space: Randomize Terrain", -1, &r[0], DT_LEFT| DT_TOP | DT_NOCLIP, 0xff000000);
  339.         m_pFont->DrawText(NULL, "1: Townhall", -1, &r[1], DT_LEFT| DT_TOP | DT_NOCLIP, 0xff000000);
  340.         m_pFont->DrawText(NULL, "2: Barracks", -1, &r[2], DT_LEFT| DT_TOP | DT_NOCLIP, 0xff000000);
  341.         m_pFont->DrawText(NULL, "3: Tower", -1, &r[3], DT_LEFT| DT_TOP | DT_NOCLIP, 0xff000000);
  342.         m_pFont->DrawText(NULL, "Left Mouse Button: Place Building", -1, &r[4], DT_LEFT| DT_TOP | DT_NOCLIP, 0xff000000);
  343.  
  344.         //FPS
  345.         char number[50];
  346.         std::string text = "FPS: ";
  347.         text += _itoa(m_lastFps, number, 10);
  348.         m_pFont->DrawText(NULL, text.c_str(), -1, &r[5], DT_LEFT| DT_TOP | DT_NOCLIP, 0xff000000);
  349.  
  350.         // End the scene.
  351.         m_pDevice->EndScene();
  352.         m_pDevice->Present(0, 0, 0, 0);
  353.     }
  354.  
  355.     return S_OK;
  356. }
  357.  
  358. HRESULT APPLICATION::Cleanup()
  359. {
  360.     try
  361.     {
  362.         m_terrain.Release();
  363.  
  364.         UnloadObjectResources();
  365.         UnloadMapObjectResources();
  366.         UnloadBuildingResources();
  367.  
  368.         for(int i=0;i<m_buildings.size();i++)
  369.             if(m_buildings[i] != NULL)
  370.                 delete m_buildings[i];
  371.         m_buildings.clear();
  372.  
  373.         m_pFont->Release();
  374.         m_pDevice->Release();
  375.  
  376.         debug.Print("Application terminated");
  377.     }
  378.     catch(...){}
  379.  
  380.     return S_OK;
  381. }
  382.  
  383. HRESULT APPLICATION::Quit()
  384. {
  385.     ::DestroyWindow(m_mainWindow);
  386.     ::PostQuitMessage(0);
  387.     return S_OK;
  388. }
  389.  
  390. int APPLICATION::GetBuilding()
  391. {
  392.     //Find closest unit
  393.     int build = -1;
  394.     float bestDist = 100000.0f;
  395.  
  396.     D3DXMATRIX world;
  397.     D3DXMatrixIdentity(&world);
  398.     m_pDevice->SetTransform(D3DTS_WORLD, &world);
  399.     RAY ray = m_mouse.GetRay();
  400.  
  401.     for(int i=0;i<m_buildings.size();i++)
  402.     {                    
  403.         float dist = ray.Intersect(m_buildings[i]->GetBoundingBox());
  404.  
  405.         if(dist >= 0.0f && dist < bestDist)
  406.         {
  407.             build = i;
  408.             bestDist = dist;
  409.         }
  410.     }
  411.  
  412.     return build;
  413. }
  414.  
  415. void APPLICATION::Select()
  416. {
  417.     try
  418.     {
  419.         if(m_mouse.ClickLeft())    // If the mouse button is pressed
  420.         {                
  421.             for(int i=0;i<m_buildings.size();i++)    //Deselect all buildings
  422.                 m_buildings[i]->m_selected = false;
  423.  
  424.             int build = GetBuilding();
  425.  
  426.             if(build > -1)m_buildings[build]->m_selected = true;
  427.         }
  428.     }
  429.     catch(...)
  430.     {
  431.         debug.Print("Error in APPLICATION::Select()");
  432.     }
  433. }